Lesson 2

Analog to Digital

This lesson will cover how to convert analog values to digital values, how to log data and view the data over a time period.

If you remember from the last lesson, a lot of sensors are analog, meaning they can output values from a range. We also mentioned how it was troublesome because a lot of devices (such as the raspberry pi) can only read digital values, so they would not be able to directly get information from the analog sensors. In order to combat this problem, we must convert the analog values into digital values via an ADC (analog to digital converter).

In the last lesson, it was mentioned that digital values can only take on the values of $0$ or $1$. I lied. Kind of. It wasn't a lie that digital values can only be 0 or 1, however, this only applies to a single bit. But when we put more than one bit together, the different combinations of 0 and 1 may produce many unique outputs.

For example: One bit by itself can be: 0 or 1.

When we put two bits together we have four different combinations!

Second Bit First Bit
0 0
0 1
1 0
1 1

Create a table by hand for all the bit combinations of three bits. How many patterns could you find? Is there a pattern emerging for how many values $n$ number of bits can create?

By now you may notice that every time we add a bit, the number of patterns we can create is double the amount of patterns we could have created without the extra added bit, e.g. one bit has two patterns, two bits have four patterns, three bits have eight patterns, etc. In general $n$ bits can take on $2^n$ patterns.

But how can this be used to help represent analog values? Well, even though we can't represent all the values an analog sensor can output, we can represent a lot of them if we have enough bits. For example, lets say an analog signal can produce a value from 0 to 3. If we had one bit "0" would represent 0 and "1" would represent three. However, if the analog value gave us the value of 1, we wouldn't know how to represent it, and if we did, there would be a really large error. But if we had two bits, we can now have four values to represent. So $00$ could represent $0$, $01$ could represent $1$, $10$ would represent $2$ and $11$ would represent $3$. NOTE THAT $00, 01, 10, 11$ DO NOT CORRESPOND TO ZERO, ONE, TEN, ELEVEN. So now we see we can respresent four of the values from 0 to 3. If have more and more bits, we will be able to represent more and more values, and when given an analog value, we can choose the digital value that is closest to it. So an ADC takes in an analog value and returns the digital value that bests represents it.

The graph below shows an analog signal. Given a three bit resolution, can you give the digital value at certain time points? There are eight (since $2^3 = 8$) horizontal lines, each representing a bit pattern that take on the values in the range of the analog signal.

An example is worked through below. I want to know what the the digital value of the signal is at the time $1.2$. I first find the point on the analog signal that corresponds with $1.2$ on the $x$-axis

We then find the horizontal line that is closest to that point, in this case its the upper most one.

Thus, the digital value that is returned is the bit pattern that corresponds with this line. In this case its $111$.

Find the bit pattern that is returned at times $0.2$, $0.4$, $0.8$, $1.6$ and $1.8$.

So it should be clear by now that as we have more and more bits, we can be more and more accurate with our estimations. So how come we don't always use one hundred, one thousand, one million, bits to estimate our signal? Although more bits has its benefits, it also has its tradeoffs. Since we have to represent all of these bits in memory, if we have a really large bit resolution, each reading will take up more memory.

Since the raspberry pi cannot directly read in analog signals, we first process the analog signals through a $24$ bit resolution ADC, and then the pi reads the digital value from the ADC.

Data Logging

Now we know how to read data from all types of sensors, how do we use it? The first thing that we want to do before anything else is to log the data. Data logging is the collection of data over a period of time, and then analyzing the patterns in the data. We will explore how we can do this in python. Firstly we will introduce a data structure that can be used to remember and store our data. This data structure is called the list. They are essentially what they sound like, a list of items in order. The example below shows the list of integers from 1 to 10. We can print lists like we did with other entities before. In the example below, we are binding the list to a variable called one_to_ten.


In [2]:
one_to_ten = [1,2,3,4,5,6,7,8,9,10]
print one_to_ten


[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

This is great, because now we can remember values that our sensors returned at specific instances of time. There are many operations we can use to modify a list. One important one that we will use here is the append operation. Essentially what it lets us do is add an element to the end of the list. An example is shown below. Initially one_to_ten is empty, we want to see how we can fill it up. Initially we bind one_to_ten to an empty list, which is denoted by [].


In [5]:
one_to_ten = []
one_to_ten.append(1)
print one_to_ten
one_to_ten.append(2)
print one_to_ten
one_to_ten.append(3)
print one_to_ten
one_to_ten.append(4)
print one_to_ten
one_to_ten.append(5)
print one_to_ten
one_to_ten.append(6)
print one_to_ten
one_to_ten.append(7)
print one_to_ten
one_to_ten.append(8)
print one_to_ten
one_to_ten.append(9)
print one_to_ten
one_to_ten.append(10)
print one_to_ten


[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

We can see that every time we called one_to_ten.append(x), we appended x to the list. For more operations we can perform on lists, see the python documentation here.

But looking at the code above, this is quite cumbersome. It involves a lot of typing and a lot of code. Programmers are lazy, so they invented a nice little way to let us not write as much code by using loops. Loops are a construct that repeat a section of code a certain number of times, as defined by the programming. One example is shown below. This is the while loop


In [9]:
i = 1
while(i <= 10):
    print i
    i = i+1


1
2
3
4
5
6
7
8
9
10

Let me explain what the code is doing. If you remember the if/else paradigm from the previous lesson, you'll remember that the if statement takes in a boolean value, and runs the code in the if block. A while loop also does this, except when it finishes running the code, it returns back to the condition statement, and if it is still true, runs the code again, whereas an if statement will just continue. In the code above, initial i is equal to 1, which we print. We then increment i by 1, so now i = 2. Since 2 <= 10, we run the code again, and print i, then increment. We keep doing this until i is incremented to 11, at which point 11 <= 10 is not true, so the while loop terminates. Note, it is important that we increment i by 1 every time, or else the condition statement is always true.

i = 1
while(i <= 10):
    print i

Lets step through the code above. We initialize i to be 1. We check that 1 <= 10, so we print i, we then return to the coniditional statement, but it has not changed and i is still = to 1, so we print i again. You can see that this loop is never going to exit! This is known as an infinite loop and we generally try to avoid it. One important thing to remember is not to forget to increment our variable!

However, we don't necessarily have to increment by 1. We can also increment by 3. See the example below. Try to see why it produces the output.


In [10]:
i = 1;
while(i <= 10):
    print i
    i = i + 3


1
4
7
10

In the block below, write some code, using a while loop, that will print out every even number, starting from 2 and ending with 20. It should print out

2
4
6
8
10
12
14
16
18
20

In [11]:
#WRITE YOUR CODE HERE

#SOlUTION
i = 2
while(i <= 20):
    print i
    i = i+2


2
4
6
8
10
12
14
16
18
20

Now we can easily create the list one_to_ten by using a loop! Try to see if you can make one_to_ten by using append and a while loop below.


In [12]:
#WRITE YOUR CODE HERE
one_to_ten = []
#SOLUTION
i = 1
while(i <= 10):
    one_to_ten.append(i)
    i = i+1
    
print one_to_ten


[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Now we can see how we use these tools to log data from our sensors. Lets log the temperature of the room over 5 seconds.

We can get the current temperature by calling board.getTemperature() and append it to a list. Say we want to take 5 samples over the 5 seconds. This means that we take a sample every second. So we want to wait a second between additions to our list that remembers the previous temperatures. This can be done by calling time.sleep(1), which basically just tells the computer to wait 1 second before continuing. See if you can implement this data logger below.


In [14]:
#WRITE YOUR CODE BELOW
import time
#import board
temperatures = []

#SOLUTION
i = 0
while(i <= 5):
    #temperatures.append(board.getTemperature)
    i = i+1
    times.

Congratulations, you've made your first data logger! We could easily modify this code to take temperatures over an entire day, or a week, or a month, or even a year! Now we have to discuss a concept called sample rate. Simply put, a sample rate is how many samples we take a second. In the example above we had a sample rate of 1, because we took one sample every second. If we had taken 10 samples over 5 seconds, we would have a 0.5 second delay between each sample, and had a sample rate of 2, because we would have taken 2 samples every single second. In general we can see that $sample rate = \frac{total samples}{total time}$. In general a higher sample rate is good because it allows us to see more data points between points. If we have too low of a sample rate we won't be able to see any patterns/how the temperature changes, it'll just be telling us what the temperature is at certain times.

Once we have a list of our values, we can visualize it through python's plotter. The code below is written to view the temperature.


In [19]:
import matplotlib.pyplot as plot
plot.plot(temperatures)
plot.show()

In [ ]: